import argparse
from concurrent import futures
import grpc
import json
import atexit

import traceback

from flask import Flask
import flask_restful as restful
from flask_restful import reqparse

import rack_equipment_management_pb2
import rack_equipment_management_pb2_grpc

from common.setting import ConfigureDiscovery
from common.log import init, info, warn, debug, error
from common.utils import byteify
import rack_equipment_db_model
from rack_equipment_db_model import DCInfrastructureDBExecutor, RackEquipmentDBExecutor, \
                                    SwitchEquipmentDBExecutor, HostEquipmentDBExecutor

DEFAULT_CONFIG_PATH = 'service.conf'
DEFAULT_LOG_PATH = 'rack-equipment-management.log'

app = Flask('RackEquipmentManagement')
api = restful.Api(app)

def _host_info_get(**kwargs):
    """
    common function to get host information.
    :param kwargs:
    :return:
    """
    host_tbl = HostEquipmentDBExecutor()
    res = host_tbl.query(**kwargs)
    return res

def _host_info_post(**kwargs):
    """
    common function to post host information
    :param kwargs:
    :return:
    """
    host_id = kwargs["HostId"]
    host_tbl = HostEquipmentDBExecutor()
    host_tbl.insert(**kwargs)
    res = host_tbl.query(HostId=host_id)
    return res

def _host_info_put(**kwargs):
    """
    common function to put host information
    :param kwargs:
    :return:
    """
    host_tbl = HostEquipmentDBExecutor()
    ip = kwargs["IpAddress"]
    host_id = kwargs["HostId"]
    res = host_tbl.query(HostId=host_id)
    if res:
        host_tbl.update(update_dict={"IpAddress": ip}, HostId=host_id)
        res = host_tbl.query(HostId=host_id)
    else:
        raise Exception("Failed to find host by id %s, it is not existed in database."
                        % (host_id))
    return res

def _host_info_delete(**kwargs):
    """
    common function to delete host information
    :param kwargs:
    :return:
    """
    host_id = kwargs["HostId"]
    host_tbl = HostEquipmentDBExecutor()
    dres = host_tbl.delete(HostId=host_id)
    res = "Delete %d record(s) of %s successful." % (dres, host_id)
    return res

def _switch_info_get(**kwargs):
    """
    common function to get switch information.
    :param kwargs:
    :return:
    """
    sw_tbl = SwitchEquipmentDBExecutor()
    res = sw_tbl.query(**kwargs)
    return res

def _switch_info_post(**kwargs):
    """
    common function to post switch information
    :param kwargs:
    :return:
    """
    sw_tbl = SwitchEquipmentDBExecutor()
    sw_id = kwargs["SwitchId"]
    sw_tbl.insert(**kwargs)
    res = sw_tbl.query(SwitchId=sw_id)
    return res

def _switch_info_put(**kwargs):
    """
    common function to put switch information
    :param kwargs:
    :return:
    """
    sw_tbl = SwitchEquipmentDBExecutor()
    sw_id = kwargs["SwitchId"]
    update_dict = kwargs["update_dict"]

    res = sw_tbl.query(SwitchId=sw_id)
    if res:
        sw_tbl.update(update_dict=update_dict, SwitchId=sw_id)
        res = sw_tbl.query(SwitchId=sw_id)
    else:
        raise Exception("Failed to find switch by id %s, it is not existed in database."
                        % (sw_id))
    return res

def _switch_info_delete(**kwargs):
    """
    common function to delete switch information
    :param kwargs:
    :return:
    """
    sw_tbl = SwitchEquipmentDBExecutor()
    sw_id = kwargs["SwitchId"]
    dres = sw_tbl.delete(SwitchId=sw_id)
    res = "Delete %d record(s) of %s successful." % (dres, sw_id)
    return res

def _rack_info_get(**kwargs):
    """
    common function to get rack information.
    :param kwargs:
    :return:
    """
    rack_tbl = RackEquipmentDBExecutor()
    res = rack_tbl.query(**kwargs)
    return res

def _rack_info_post(**kwargs):
    """
    common function to post rack information.
    :param kwargs:
    :return:
    """
    rack_tbl = RackEquipmentDBExecutor()
    rack_id = kwargs["RackId"]
    rack_tbl.insert(**kwargs)
    res = rack_tbl.query(RackId=rack_id)
    return res

def _rack_info_put(**kwargs):
    """
    common function to put rack information.
    :param kwargs:
    :return:
    """
    rack_tbl = RackEquipmentDBExecutor()
    rack_id = kwargs["RackId"]
    res = rack_tbl.query(RackId=rack_id)
    if res:
        rack_tbl.update(**kwargs)
        res = rack_tbl.query(RackId=rack_id)
    else:
        raise Exception("Failed to find rack by id %s, it is not existed in database."
                        % (rack_id))
    return res

def _rack_info_delete(**kwargs):
    """
    common function to delete rack information.
    :param kwargs:
    :return:
    """
    rack_tbl = RackEquipmentDBExecutor()
    rack_id = kwargs["RackId"]
    dres = rack_tbl.delete(RackId=rack_id)
    res = "Delete %d record(s) of %s successful." % (dres, rack_id)
    return res

def _dc_info_get(**kwargs):
    """
    common function to get dc information.
    :param kwargs:
    :return:
    """
    dc_tbl = DCInfrastructureDBExecutor()
    res = dc_tbl.query(**kwargs)
    return res

def _dc_info_post(**kwargs):
    """
    common function to post dc information.
    :param kwargs:
    :return:
    """
    dc_tbl = DCInfrastructureDBExecutor()
    dc_id = kwargs["DataCenterId"]
    dc_tbl.insert(**kwargs)
    res = dc_tbl.query(DataCenterId=dc_id)
    return res

def _dc_info_put(**kwargs):
    """
    common function to put dc information.
    :param kwargs:
    :return:
    """
    dc_tbl = DCInfrastructureDBExecutor()
    dc_id = kwargs["DataCenterId"]

    res = dc_tbl.query(DataCenterId=dc_id)
    if res:
        dc_tbl.update(**kwargs)
        res = dc_tbl.query(DataCenterId=dc_id)
    else:
        raise Exception("Failed to find dc by id %s, it is not existed in database."
                        % (dc_id))
    return res

def _dc_info_delete(**kwargs):
    """
    common function to delete dc information.
    :param kwargs:
    :return:
    """
    dc_tbl = DCInfrastructureDBExecutor()
    dc_id = kwargs["DataCenterId"]
    dres = dc_tbl.delete(**kwargs)
    res = "Delete %d record(s) of %s successful." % (dres, dc_id)
    return res

class RackEquipmentManagement(rack_equipment_management_pb2_grpc.RackEquipmentManagementServicer):

    def HostInfoGet(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            if "host_id" in req:
                kwargs["HostId"] = req["host_id"]
            res = _host_info_get(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def HostInfoPost(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            kwargs["HostId"] = req["host_id"]
            kwargs["IpAddress"] = req["ip"]
            res = _host_info_post(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def HostInfoPut(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            kwargs["HostId"] = req["host_id"]
            kwargs["IpAddress"] = req["ip"]
            res = _host_info_put(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def HostInfoDelete(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            kwargs["HostId"] = req["host_id"]
            res = _host_info_delete(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def SwitchInfoGet(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            if "sw_id" in req:
                kwargs["SwitchId"] = req["sw_id"]
            res = _switch_info_get(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def SwitchInfoPost(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            kwargs["SwitchId"] = req["sw_id"]
            kwargs["IpAddress"] = req["ip"]
            kwargs["GatewayMac"] = req["gateway_mac"]
            kwargs["RemoteVtep"] = req["remote_vtep"]
            kwargs["SwitchPort"] = req["switch_port"]
            kwargs["VVlanIp"] = req["vvlan_ip"]
            kwargs["Vtep"] = req["vtep"]
            kwargs["Type"] = req["type"]
            kwargs["Description"] = req["description"]
            kwargs["Manufacturer"] = req["manufacturer"]
            res = _switch_info_post(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def SwitchInfoPut(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            update_dict = {}
            if "ip" in req and req["ip"]:
                update_dict["IpAddress"] = req["ip"]
            if "gateway_mac" in req and req["gateway_mac"]:
                update_dict["GatewayMac"] = req["gateway_mac"]
            if "remote_vtep" in req and req["remote_vtep"]:
                update_dict["RemoteVtep"] = req["remote_vtep"]
            if "switch_port" in req and req["switch_port"]:
                update_dict["SwitchPort"] = req["switch_port"]
            if "vtep" in req and req["vtep"]:
                update_dict["Vtep"] = req["vtep"]
            if "description" in req and req["description"]:
                update_dict["Description"] = req["description"]
            if "vvlan_ip" in req and req["vvlan_ip"]:
                update_dict["VVlanIp"] = req["vvlan_ip"]
            if "type" in req and req["type"]:
                update_dict["Type"] = req["type"]
            if "manufacturer" in req and req["manufacturer"]:
                update_dict["Manufacturer"] = req["manufacturer"]

            kwargs["update_dict"] = update_dict
            kwargs["SwitchId"] = req["sw_id"]
            res = _switch_info_put(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def SwitchInfoDelete(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            sw_id = req["sw_id"]
            res = _switch_info_delete(SwitchId=sw_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def RackInfoGet(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            if "rack_id" in req:
                kwargs["RackId"] = req["rack_id"]
            res = _rack_info_get(**kwargs)

        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def RackInfoPost(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            kwargs["RackId"] = req["rack_id"]
            kwargs["RackName"] = req["rack_name"]
            res = _rack_info_post(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def RackInfoPut(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            update_dict = {}

            if "rack_name" in req and req["rack_name"]:
                update_dict["RackName"] = req["rack_name"]

            kwargs["update_dict"] = update_dict
            kwargs["RackId"] = req["rack_id"]

            res = _rack_info_put(**kwargs)

        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def RackInfoDelete(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            rack_id = req["rack_id"]
            res = _rack_info_delete(RackId=rack_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def DCInfoGet(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {}
            for k, v in req.items():
                if "dc_id" in k and v:
                    kwargs["%sDataCenterId" % ("not_" if "!" == k[0] else "")] = v
                if "rack_id" in k and v:
                    kwargs["%sRackId" % ("not_" if "!" == k[0] else "")] = v
                if "sw_id" in k and v:
                    kwargs["%sSwitchId" % ("not_" if "!" == k[0] else "")] = v
                if "virtualize_tec" in args and args["virtualize_tec"]:
                    kwargs["%sVirtualizeTec" % ("not_" if "!" == k[0] else "")] = v
                if "host_id" in k and v:
                    kwargs["%sHostId" % ("not_" if "!" == k[0] else "")] = v
                if "extend_info" in k and v:
                    kwargs["%sExtendInfo" % ("not_" if "!" == k[0] else "")] = v
            res = _dc_info_get(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def DCInfoPost(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {"DataCenterId": req["dc_id"]}
            kwargs["RackId"] = req["rack_id"]
            kwargs["SwitchId"] = req["sw_id"]
            kwargs["HostId"] = req["host_id"]
            kwargs["VirtualizeTec"] = req["virtualize_tec"]
            if "extend_info" in req and req["extend_info"]:
                kwargs["ExtendInfo"] = req["extend_info"]
            res = _dc_info_post(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def DCInfoPut(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {"DataCenterId": req["dc_id"]}
            update_dict = {}
            if "condition" in req and req["condition"]:
                for c in req["condition"]:
                    n_c = c[1:] if "!" == c[0] else c
                    if "rack_id" in c and req[n_c]:
                        kwargs["%sRackId" % ("not_" if "!" == c[0] else "")] = req[n_c]
                        del req[n_c]
                    if "sw_id" in c and req[n_c]:
                        kwargs["%sSwitchId" % ("not_" if "!" == c[0] else "")] = req[n_c]
                        del req[n_c]
                    if "virtualize_tec" in c and req[n_c]:
                        kwargs["%sVirtualizeTec" % ("not_" if "!" == c[0] else "")] = req[n_c]
                        del req[n_c]
                    if "host_id" in c and req[n_c]:
                        kwargs["%sHostId" % ("not_" if "!" == c[0] else "")] = req[n_c]
                        del req[n_c]
                    if "extend_info" in c and req[n_c]:
                        kwargs["%sExtendInfo" % ("not_" if "!" == c[0] else "")] = req[n_c]
                        del req[n_c]

            for k, v in req.items():
                if "rack_id" == k and v:
                    update_dict["RackId"] = v
                if "sw_id" == k and v:
                    update_dict["SwitchId"] = v
                if "host_id" == k and v:
                    update_dict["HostId"] = v
                if "virtualize_tec" == k and v:
                    update_dict["VirtualizeTec"] = v
                if "extend_info" == k and v:
                    update_dict["ExtendInfo"] = v
            kwargs["update_dict"] = update_dict
            res = _dc_info_put(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

    def DCInfoDelete(self, request, context):
        res = None
        status_code = 200
        try:
            req = json.loads(request.req)
            kwargs = {"DataCenterId": req["dc_id"]}
            for k, v in req.items():
                if "rack_id" in k and v:
                    kwargs["%sRackId" % ("not_" if "!" == k[0] else "")] = v
                if "sw_id" in k and v:
                    kwargs["%sSwitchId" % ("not_" if "!" == k[0] else "")] = v
                if "virtualize_tec" in k and v:
                    kwargs["%sVirtualizeTec" % ("not_" if "!" == k[0] else "")] = v
                if "host_id" in k and v:
                    kwargs["%sHostId" % ("not_" if "!" == k[0] else "")] = v
                if "extend_info" in k and v:
                    kwargs["%sExtendInfo" % ("not_" if "!" == k[0] else "")] = v

            res = _dc_info_delete(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return rack_equipment_management_pb2.ServerReply(status_code=status_code, res=json.dumps(res))

def GrpcServer(host, port):
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    rack_equipment_management_pb2_grpc.add_RackEquipmentManagementServicer_to_server(RackEquipmentManagement(), server)
    server.add_insecure_port('%s:%d' % (host, port))
    server.start()
    atexit.register(server.stop, *[0])

class DCListAPI(restful.Resource):
    """
    All dc query apis.
    """
    def get(self):
        """
        Get all DC information by dc id.
        :param dc_id: DC id.
        :return: DC information.
        """
        res = None
        status_code = 200
        try:
            args = dc_req_arg_parser()
            kwargs = {}
            for k, v in args.items():
                if "dc_id" in k and v:
                    kwargs["%sDataCenterId" % ("not_" if "!"==k[0] else "")] = v
                if "rack_id" in k and v:
                    kwargs["%sRackId" % ("not_" if "!"==k[0] else "")] = v
                if "sw_id" in k and v:
                    kwargs["%sSwitchId" % ("not_" if "!"==k[0] else "")] = v
                if "virtualize_tec" in k and v:
                    kwargs["%sVirtualizeTec" % ("not_" if "!"==k[0] else "")] = v
                if "host_id" in k and v:
                    kwargs["%sHostId" % ("not_" if "!"==k[0] else "")] = v
                if "extend_info" in k and v:
                    kwargs["%sExtendInfo" % ("not_" if "!"==k[0] else "")] = v
            res = _dc_info_get(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

class DCAPI(restful.Resource):
    """
    Single DC management api.
    """
    def get(self, dc_id):
        """
        Get DC information by dc id.
        :param dc_id: DC id.
        :return: DC information.
        """
        res = None
        status_code = 200
        try:
            args = dc_req_arg_parser()
            kwargs = {"DataCenterId": dc_id}
            if "rack_id" in args and args["rack_id"]:
                kwargs["RackId"] = args["rack_id"]
            if "sw_id" in args and args["sw_id"]:
                kwargs["SwitchId"] = args["sw_id"]
            if "virtualize_tec" in args and args["virtualize_tec"]:
                kwargs["VirtualizeTec"] = args["virtualize_tec"]
            if "host_id" in args and args["host_id"]:
                kwargs["HostId"] = args["host_id"]
            if "extend_info" in args and args["extend_info"]:
                kwargs["ExtendInfo"] = args["extend_info"]
            res = _dc_info_get(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def post(self, dc_id):
        """
        Add DC information by dc id.
        :param dc_id: DC id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = dc_req_arg_parser()
            kwargs = {"DataCenterId": dc_id}
            kwargs["RackId"] = args["rack_id"]
            kwargs["SwitchId"] = args["sw_id"]
            kwargs["HostId"] = args["host_id"]
            kwargs["VirtualizeTec"] = args["virtualize_tec"]
            kwargs["ExtendInfo"] = args["extend_info"]
            res = _dc_info_post(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def put(self, dc_id):
        """
        Modify DC information by dc id.
        :param dc_id: DC id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = dc_req_arg_parser()
            kwargs = {"DataCenterId":dc_id}
            update_dict = {}
            if "condition" in args and args["condition"]:
                for c in args["condition"]:
                    n_c = c[1:] if "!" == c[0] else c
                    if "rack_id" in c and args[n_c]:
                        kwargs["%sRackId" % ("not_" if "!" == c[0] else "")] = args[n_c]
                        del args[n_c]
                    if "sw_id" in c and args[n_c]:
                        kwargs["%sSwitchId" % ("not_" if "!" == c[0] else "")] = args[n_c]
                        del args[n_c]
                    if "virtualize_tec" in c and args[n_c]:
                        kwargs["%sVirtualizeTec" % ("not_" if "!" == c[0] else "")] = args[n_c]
                        del args[n_c]
                    if "host_id" in c and args[n_c]:
                        kwargs["%sHostId" % ("not_" if "!" == c[0] else "")] = args[n_c]
                        del args[n_c]
                    if "extend_info" in c and args[n_c]:
                        kwargs["%sExtendInfo" % ("not_" if "!" == c[0] else "")] = args[n_c]
                        del args[n_c]

            for k, v in args.items():
                if "rack_id" == k and v:
                    update_dict["RackId"] = v
                if "sw_id" == k and v:
                    update_dict["SwitchId"] = v
                if "host_id" == k and v:
                    update_dict["HostId"] = v
                if "virtualize_tec" == k and v:
                    update_dict["VirtualizeTec"] = v
                if "extend_info" == k and v:
                    update_dict["ExtendInfo"] = v
            kwargs["update_dict"] = update_dict
            res = _dc_info_put(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def delete(self, dc_id):
        """
        Delete DC information by dc id.
        :param dc_id: DC id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = dc_req_arg_parser()
            kwargs = {"DataCenterId":dc_id}
            for k, v in args.items():
                if "rack_id" in k and v:
                    kwargs["%sRackId" % ("not_" if "!" == k[0] else "")] = v
                if "sw_id" in k and v:
                    kwargs["%sSwitchId" % ("not_" if "!" == k[0] else "")] = v
                if "virtualize_tec" in k and v:
                    kwargs["%sVirtualizeTec" % ("not_" if "!" == k[0] else "")] = v
                if "host_id" in k and v:
                    kwargs["%sHostId" % ("not_" if "!" == k[0] else "")] = v
                if "extend_info" in k and v:
                    kwargs["%sExtendInfo" % ("not_" if "!" == k[0] else "")] = v

            res = _dc_info_delete(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

class RackListAPI(restful.Resource):
    """
    All racks query apis.
    """
    def get(self):
        """
        Get All rack information by rack id.
        :param rack_id: Rack id.
        :return: Rack information.
        """
        res = None
        status_code = 200
        try:
            res = _rack_info_get()
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

class RackAPI(restful.Resource):
    """
    Single rack management api.
    """
    def get(self, rack_id):
        """
        Get Rack information by rack id.
        :param rack_id: Rack id.
        :return: Rack information.
        """
        res = None
        status_code = 200
        try:
            res = _rack_info_get(RackId=rack_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def post(self, rack_id):
        """
        Add Rack information with rack id.
        :param rack_id: Rack id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = rack_req_arg_parser()
            rack_name = args["rack_name"]
            res = _rack_info_post(RackId=rack_id, RackName=rack_name)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def put(self, rack_id):
        """
        Modify Rack information with rack id.
        :param rack_id: Rack id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = rack_req_arg_parser()
            rack_name = args["rack_name"]
            res = _rack_info_put(update_dict={"RackName": rack_name}, RackId=rack_id)

        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def delete(self, rack_id):
        """
        Delete Rack information with rack id.
        :param rack_id: Rack id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            res = _rack_info_delete(RackId=rack_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

class SwitchListAPI(restful.Resource):
    """
    All switches query apis.
    """
    def get(self):
        """
        Get all switch information by switch id.
        :return: Tor switch information.
        """
        res = None
        status_code = 200
        try:
            res = _switch_info_get()
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

class SwitchAPI(restful.Resource):
    """
    Single switch management api
    """
    def get(self, sw_id):
        """
        Get switch information by switch id.
        :param id: switch id.
        :return: switch information.
        """
        res = None
        status_code = 200
        try:
            res = _switch_info_get(SwitchId=sw_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def post(self, sw_id):
        """
        Add switch information with switch id.
        :param sw_id: switch id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = sw_req_arg_parser()
            kwargs = {}
            kwargs["SwitchId"] = sw_id
            kwargs["IpAddress"] = args["ip"]
            kwargs["GatewayMac"] = args["gateway_mac"]
            kwargs["RemoteVtep"] = args["remote_vtep"]
            kwargs["SwitchPort"] = args["switch_port"]
            kwargs["VVlanIp"] = args["vvlan_ip"]
            kwargs["Vtep"] = args["vtep"]
            kwargs["Type"] = args["type"]
            kwargs["Description"] = args["description"]
            kwargs["Manufacturer"] = args["manufacturer"]
            res = _switch_info_post(**kwargs)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def put(self, sw_id):
        """
        Modify switch information with switch id.
        :param sw_id: switch id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = sw_req_arg_parser()
            update_dict = {}
            if "ip" in args and args["ip"]:
                update_dict["IpAddress"] = args["ip"]
            if "gateway_mac" in args and args["gateway_mac"]:
                update_dict["GatewayMac"] = args["gateway_mac"]
            if "remote_vtep" in args and args["remote_vtep"]:
                update_dict["RemoteVtep"] = args["remote_vtep"]
            if "switch_port" in args and args["switch_port"]:
                update_dict["SwitchPort"] = args["switch_port"]
            if "vtep" in args and args["vtep"]:
                update_dict["Vtep"] = args["vtep"]
            if "description" in args and args["description"]:
                update_dict["Description"] = args["description"]
            if "vvlan_ip" in args and args["vvlan_ip"]:
                update_dict["VVlanIp"] = args["vvlan_ip"]
            if "type" in args and args["type"]:
                update_dict["Type"] = args["type"]
            if "manufacturer" in args and args["manufacturer"]:
                update_dict["Manufacturer"] = args["manufacturer"]

            res = _switch_info_put(update_dict=update_dict, SwitchId=sw_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def delete(self, sw_id):
        """
        Delete switch information with switch id.
        :param sw_id: switch id.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            res = _switch_info_delete(SwitchId=sw_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

class HostListAPI(restful.Resource):
    """
    All Hosts query apis.
    """
    def get(self):
        """
        Get all host information.
        :return: all host information.
        """
        res = None
        status_code = 200
        try:
            res = _host_info_get()
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

class HostAPI(restful.Resource):
    """
    Single host management api
    """
    def get(self, host_id):
        """
        Get host information by host id.
        :param host_id: host id must be same with the
                        id assigned by related virtulize
                        platform for the host.
        :return: host information.
        """
        res = None
        status_code = 200
        try:
            res = _host_info_get(HostId=host_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def post(self, host_id):
        """
        Add host information with host id.
        :param host_id: host id must be same with the
                        id assigned by related virtulize
                        platform for the host.
        :return: if add successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = host_req_arg_parser()
            ip = args["ip"]
            res = _host_info_post(HostId=host_id, IpAddress=ip)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def put(self, host_id):
        """
        Modify host information with host id.
        :param host_id: host id must be same with the
                        id assigned by related virtulize
                        platform for the host.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            args = host_req_arg_parser()
            ip = args["ip"]
            res = _host_info_put(HostId=host_id, IpAddress=ip)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

    def delete(self, host_id):
        """
        Delete host information by host id.
        :param host_id: host id must be same with the
                        id assigned by related virtulize
                        platform for the host.
        :return: if modify successful, the successful message will be return.
        """
        res = None
        status_code = 200
        try:
            res = _host_info_delete(HostId=host_id)
        except Exception as ex:
            error(traceback.format_exc())
            error(ex)
            res = str(ex)
            status_code = 403

        return {"status": status_code, "result": res}, status_code

api.add_resource(DCListAPI, '/dc')
api.add_resource(DCAPI, '/dc/<string:dc_id>')
api.add_resource(RackListAPI, '/rack')
api.add_resource(RackAPI, '/rack/<string:rack_id>')
api.add_resource(SwitchListAPI, '/switch')
api.add_resource(SwitchAPI, '/switch/<string:sw_id>')
api.add_resource(HostListAPI, '/host')
api.add_resource(HostAPI, '/host/<string:host_id>')

def _str2bool(v):
    return v.lower() in ("yes", "true", "t", "ok", "1")

def argument_parser():
    parser = argparse.ArgumentParser(description="Aliyun ECS Operation CLI.")

    parser.add_argument("-c", "--config", action="store", type=str, dest="conf_path",
                        help="Server config file.", required=False, default=DEFAULT_CONFIG_PATH)
    parser.add_argument("-l", "--log-path", action="store", type=str, dest="log_path",
                        help="Server log path.", required=False, default=DEFAULT_LOG_PATH)
    parser.add_argument("-H", "--host", action="store", type=str, dest="host",
                        help="Server bind host address.", required=False, default="0.0.0.0")
    parser.add_argument("-P", "--port", action="store", type=int, dest="port",
                        help="Server bind host port for restful server.", required=False, default=5000)
    parser.add_argument("-R", "--rpc-port", action="store", type=int, dest="rpc_port",
                        help="Server bind host port for rpc server.", required=False, default=50051)
    parser.add_argument("-d", "--debug", action="store", type=_str2bool, dest="debug",
                        help="Enable service debug information.", required=False, default=True)

    return parser.parse_args()

def host_req_arg_parser():
    parser = reqparse.RequestParser()
    parser.add_argument('ip', type=str, required=True)
    return parser.parse_args()

def sw_req_arg_parser():
    parser = reqparse.RequestParser()
    parser.add_argument('description', type=str)
    parser.add_argument('ip', type=str)
    parser.add_argument('gateway_mac', type=str)
    parser.add_argument('remote_vtep', type=str)
    parser.add_argument('manufacturer', type=unicode)
    parser.add_argument('vvlan_ip', type=int, help='VVlan ip cannot be converted')
    parser.add_argument('switch_port', type=str)
    parser.add_argument('vtep', type=int, help='Vtep cannot be converted')
    parser.add_argument('type', type=str)
    return byteify(parser.parse_args())

def rack_req_arg_parser():
    parser = reqparse.RequestParser()
    parser.add_argument('rack_name', type=str, required=True)
    return parser.parse_args()

def dc_req_arg_parser():
    parser = reqparse.RequestParser()
    parser.add_argument('dc_id', type=str)
    parser.add_argument('rack_id', type=str)
    parser.add_argument('sw_id', type=str)
    parser.add_argument('host_id', type=str)
    parser.add_argument('virtualize_tec', type=str)
    parser.add_argument('extend_info', type=str)
    parser.add_argument('!dc_id', type=str)
    parser.add_argument('!rack_id', type=str)
    parser.add_argument('!sw_id', type=str)
    parser.add_argument('!host_id', type=str)
    parser.add_argument('!virtualize_tec', type=str)
    parser.add_argument('!extend_info', type=str)
    parser.add_argument('condition', action='append', location='args')
    return parser.parse_args()

if __name__ == '__main__':
    args = argument_parser()
    init(logpath=args.log_path, log_level='DEBUG' if args.debug else 'INFO')
    cd = ConfigureDiscovery()
    cd.start_observe_conf(conf_file=args.conf_path)
    cd.regist_observer('db', rack_equipment_db_model.notify)
    cd.notify()
    GrpcServer(host=args.host, port=args.rpc_port)
    app.run(host=args.host, port=args.port, debug=args.debug)
